﻿//-----------------------------------------------------------------------
// <copyright file="DiagnosticsServiceClient.cs" company="CodePlex">
//     Copyright (c) Doug Holland, CodePlex. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace CodePlex.Diagnostics.Silverlight
{
    using System;

    using System.Collections;
    using System.Collections.Generic;

    using System.ComponentModel;

    using System.Reflection;

    using System.Security;
    using System.Security.Principal;

    using System.ServiceModel;
    using System.ServiceModel.Channels;

    using System.Threading;

    using System.Xml;
    using System.Xml.Linq;

    using CodePlex.Diagnostics.Silverlight.Contracts;

    /// <summary>
    /// Implements the <see cref="T:IDiagnosticsService"/> interface and provides a Windows Communication Foundation (WCF) client to enable asynchronous service calls.
    /// </summary>
    public sealed class DiagnosticsServiceClient : ClientBase<IDiagnosticsService>, IDiagnosticsService
    {
        #region DiagnosticsServiceClient Private Fields

        /// <summary>
        /// Synchronization lock used for thread synchronization.
        /// </summary>
        private static object synchronizationLock = new object();

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client to begin the publication of an exception. 
        /// </summary>
        private BeginOperationDelegate onBeginPublishExceptionDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndPublishExceptionDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onPublishExceptionCompletedDelegate;

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client to begin the publication of a log entry.
        /// </summary>
        private BeginOperationDelegate onBeginLogDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndLogDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onLogCompletedDelegate;

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client to begin the update of process exit information.
        /// </summary>
        private BeginOperationDelegate onBeginUpdateProcessExitInformationDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndUpdateProcessExitInformationDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onUpdateProcessExitInformationCompletedDelegate;

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client to begin the registration of a team foundation server instance.
        /// </summary>
        private BeginOperationDelegate onBeginRegisterTeamFoundationServerDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndRegisterTeamFoundationServerDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onRegisterTeamFoundationServerCompletedDelegate;

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client.
        /// </summary>
        private BeginOperationDelegate onBeginOpenDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndOpenDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onOpenCompletedDelegate;

        /// <summary>
        /// A delegate that is used by for calling asynchronous operations on the client.
        /// </summary>
        private BeginOperationDelegate onBeginCloseDelegate;

        /// <summary>
        /// A delegate that is invoked on successful completion of the asynchronous call. 
        /// </summary>
        private EndOperationDelegate onEndCloseDelegate;

        /// <summary>
        /// A delegate representing a method to be called when a message is to be dispatched to a synchronization context.
        /// </summary>
        private SendOrPostCallback onCloseCompletedDelegate;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.PublishExceptionCompleted"/> event.
        /// </summary>
        private EventHandler<PublishExceptionCompletedEventArgs> publishExceptionCompleted;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.LogCompleted"/> event.
        /// </summary>
        private EventHandler<LogCompletedEventArgs> logCompleted;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.UpdateProcessExitInformationCompleted"/> event.
        /// </summary>
        private EventHandler<AsyncCompletedEventArgs> updateProcessExitInformationCompleted;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.RegisterTeamFoundationServerCompleted"/> event.
        /// </summary>
        private EventHandler<AsyncCompletedEventArgs> registerTeamFoundationServerCompleted;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.OpenCompleted"/> event.
        /// </summary>
        private EventHandler<AsyncCompletedEventArgs> openCompleted;

        /// <summary>
        /// A delegate representing the method that will handle the <see cref="M:DiagnosticsServiceClient.CloseCompleted"/> event.
        /// </summary>
        private EventHandler<AsyncCompletedEventArgs> closeCompleted;

        #endregion

        #region public DiagnosticsServiceClient()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:DiagnosticsServiceClient"/> class.
        /// </summary>
        public DiagnosticsServiceClient()
        {
        }

        #endregion

        #region public DiagnosticsServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)

        /// <summary>
        /// Initializes a new instance of the <see cref="DiagnosticsServiceClient"/> class.
        /// </summary>
        /// <param name="endpointConfigurationName">The name of the endpoint in the application configuration file.</param>
        public DiagnosticsServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)
        {
        }

        #endregion

        #region public DiagnosticsServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress)

        /// <summary>
        /// Initializes a new instance of the <see cref="DiagnosticsServiceClient"/> class.
        /// </summary>
        /// <param name="endpointConfigurationName">The name of the endpoint in the application configuration file.</param>
        /// <param name="remoteAddress">The address of the service endpoint.</param>
        public DiagnosticsServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress)
        {
        }

        #endregion

        #region public DiagnosticsServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress)

        /// <summary>
        /// Initializes a new instance of the <see cref="DiagnosticsServiceClient"/> class.
        /// </summary>
        /// <param name="endpointConfigurationName">The name of the endpoint in the application configuration file.</param>
        /// <param name="remoteAddress">The address of the service endpoint.</param>
        public DiagnosticsServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress)
        {
        }

        #endregion

        #region public DiagnosticsServiceClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress)

        /// <summary>
        /// Initializes a new instance of the <see cref="DiagnosticsServiceClient"/> class.
        /// </summary>
        /// <param name="binding">The binding with which to make calls to the service.</param>
        /// <param name="remoteAddress">The address of the service endpoint.</param>
        public DiagnosticsServiceClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress)
        {
        }

        #endregion

        #region public event EventHandler<PublishExceptionCompletedEventArgs> PublishExceptionCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the publication of an exception.
        /// </summary>
        public event EventHandler<PublishExceptionCompletedEventArgs> PublishExceptionCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.publishExceptionCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.publishExceptionCompleted -= value;
                }
            }
        }

        #endregion

        #region public event EventHandler<LogCompletedEventArgs> LogCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the publication of a log entry.
        /// </summary>
        public event EventHandler<LogCompletedEventArgs> LogCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.logCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.logCompleted -= value;
                }
            }
        }

        #endregion

        #region public event EventHandler<AsyncCompletedEventArgs> UpdateProcessExitInformationCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the update of process exit information.
        /// </summary>
        public event EventHandler<AsyncCompletedEventArgs> UpdateProcessExitInformationCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.updateProcessExitInformationCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.updateProcessExitInformationCompleted -= value;
                }
            }
        }

        #endregion

        #region public event EventHandler<AsyncCompletedEventArgs> RegisterTeamFoundationServerCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the registration of a Team Foundation Server instance.
        /// </summary>
        public event EventHandler<AsyncCompletedEventArgs> RegisterTeamFoundationServerCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.registerTeamFoundationServerCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.registerTeamFoundationServerCompleted -= value;
                }
            }
        }

        #endregion

        #region public event EventHandler<AsyncCompletedEventArgs> OpenCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the opening of the channel.
        /// </summary>
        public event EventHandler<AsyncCompletedEventArgs> OpenCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.openCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.openCompleted -= value;
                }
            }
        }

        #endregion

        #region public event EventHandler<AsyncCompletedEventArgs> CloseCompleted

        /// <summary>
        /// The event handler that is invoked when the <see cref="T:DiagnosticsServiceClient"/> object has completed the closing of the channel.
        /// </summary>
        public event EventHandler<AsyncCompletedEventArgs> CloseCompleted
        {
            add
            {
                lock (synchronizationLock)
                {
                    this.closeCompleted += value;
                }
            }

            remove
            {
                lock (synchronizationLock)
                {
                    this.closeCompleted -= value;
                }
            }
        }

        #endregion

        #region IAsyncResult IDiagnosticsService.BeginPublishException(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state);

        /// <summary>
        /// Begins an asynchronous operation that publishes the exception information contained within the specified <see cref="T:CodePlex.Diagnostics.Contracts.ExceptionDataContract"/> to the database.
        /// </summary>
        /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.ExceptionDataContract"/> containing the exception information to be published to the database.</param>
        /// <param name="dictionary">A <see cref="T:Collections.Generic.Dictionary`2"/> containing name value pairs associated with this exception.</param>
        /// <param name="element">A <see cref="T:Xml.Linq.XElement"/> representing an xml element to be associated with this exception.</param>
        /// <param name="identity">The <see cref="T:CodePlex.Diagnostics.Contracts.IIdentityDataContract"/> containing the identity information to be published to the database.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
        /// <param name="state">A user-provided state object.</param>
        /// <returns>An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        IAsyncResult IDiagnosticsService.BeginPublishException(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)
        {
            return Channel.BeginPublishException(contract, dictionary, element, identity, callback, state);
        }

        #endregion

        #region Guid IDiagnosticsService.EndPublishException(IAsyncResult result)

        /// <summary>
        /// Ends an asynchronous operation to publish an exception.
        /// </summary>
        /// <param name="result">The result of the asynchronous operation to publish an exception.</param>
        /// <returns>A <see cref="T:Guid"/> containing the publication Id of the exception published to the database.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        Guid IDiagnosticsService.EndPublishException(IAsyncResult result)
        {
            return Channel.EndPublishException(result);
        }

        #endregion

        #region private IAsyncResult OnBeginPublishException(object[] values, AsyncCallback callback, object state)

        /// <summary>
        /// Begins an asynchronous operation to publish an exception.
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
        /// <param name="state">A user-provided state object.</param>
        /// <returns>An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
        private IAsyncResult OnBeginPublishException(object[] values, AsyncCallback callback, object state)
        {
            ExceptionDataContract contract = values[0] as ExceptionDataContract;

            Dictionary<string, string> dictionary = values[1] as Dictionary<string, string>;

            XElement element = values[2] as XElement;

            IIdentityDataContract identity = values[3] as IIdentityDataContract;

            return ((IDiagnosticsService)this).BeginPublishException(contract, dictionary, element, identity, callback, state);
        }

        #endregion

        #region private object[] OnEndPublishException(IAsyncResult result)

        /// <summary>
        /// Ends an asynchronous operation to publish an exception.
        /// </summary>
        /// <param name="result">The <see cref="T:IAsyncResult"/> returned by a call to the <see cref="M:DiagnosticsServiceClient.OnBeginPublishException"/> method.</param>
        /// <returns></returns>
        private object[] OnEndPublishException(IAsyncResult result)
        {
            return new object[] 
            {
                ((IDiagnosticsService)this).EndPublishException(result)
            };
        }

        #endregion

        #region private void OnPublishExceptionCompleted(object state)

        /// <summary>
        /// Called when [publish exception completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnPublishExceptionCompleted(object state)
        {
            if (this.publishExceptionCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;
                this.publishExceptionCompleted(this, new PublishExceptionCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void PublishException(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity)

        /// <summary>
        /// Publishes the exception async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="element">The element.</param>
        /// <param name="identity">The identity.</param>
        public void PublishExceptionAsync(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity)
        {
            this.PublishExceptionAsync(contract, dictionary, element, identity, null);
        }

        #endregion

        #region public void PublishExceptionAsync(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, object state)

        /// <summary>
        /// Publishes the exception async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="element">The element.</param>
        /// <param name="identity">The identity.</param>
        /// <param name="state">The state.</param>
        public void PublishExceptionAsync(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, object state)
        {
            if (this.onBeginPublishExceptionDelegate == null)
            {
                this.onBeginPublishExceptionDelegate = new BeginOperationDelegate(this.OnBeginPublishException);
            }

            if (this.onEndPublishExceptionDelegate == null)
            {
                this.onEndPublishExceptionDelegate = new EndOperationDelegate(this.OnEndPublishException);
            }

            if (this.onPublishExceptionCompletedDelegate == null)
            {
                this.onPublishExceptionCompletedDelegate = new SendOrPostCallback(this.OnPublishExceptionCompleted);
            }

            base.InvokeAsync(
                this.onBeginPublishExceptionDelegate, 
                new object[] { contract, dictionary, element, identity }, 
                this.onEndPublishExceptionDelegate, 
                this.onPublishExceptionCompletedDelegate, 
                state);
        }

        #endregion

        #region IAsyncResult IDiagnosticsService.BeginLog(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)

        /// <summary>
        /// Begins an asynchronous operation that writes the <see cref="T:String"/> using the configured logging provider.
        /// </summary>
        /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.LogEntryDataContract"/> containing the log entry information to be published to the database.</param>
        /// <param name="dictionary">A <see cref="T:Collections.Generic.Dictionary`2"/> containing name value pairs associated with this log entry.</param>
        /// <param name="element">A <see cref="T:Xml.Linq.XElement"/> representing an xml element to be associated with this log entry.</param>
        /// <param name="identity">The <see cref="T:CodePlex.Diagnostics.Contracts.IIdentityDataContract"/> containing the identity information to be published to the database.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete. </param>
        /// <param name="state">A user-provided state object.</param>
        /// <returns>An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        IAsyncResult IDiagnosticsService.BeginLog(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)
        {
            return Channel.BeginLog(contract, dictionary, element, identity, callback, state);
        }

        #endregion

        #region Guid IDiagnosticsService.EndLog(IAsyncResult result)

        /// <summary>
        /// Ends an asynchronous operation to write the specified log entry to the database.
        /// </summary>
        /// <param name="result">The result of the asynchronous operation to write the specified log entry to the database.</param>
        /// <returns>A <see cref="T:Guid"/> containing the publication Id of the log entry written to the database.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        Guid IDiagnosticsService.EndLog(IAsyncResult result)
        {
            return Channel.EndLog(result);
        }

        #endregion

        #region private IAsyncResult OnBeginLog(object[] values, AsyncCallback callback, object state)

        /// <summary>
        /// Called when [begin log].
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private IAsyncResult OnBeginLog(object[] values, AsyncCallback callback, object state)
        {
            LogEntryDataContract contract = values[0] as LogEntryDataContract;

            Dictionary<string, string> dictionary = values[1] as Dictionary<string, string>;
            
            XElement element = values[2] as XElement;
            
            IIdentityDataContract identity = values[3] as IIdentityDataContract;

            return ((IDiagnosticsService)this).BeginLog(contract, dictionary, element, identity, callback, state);
        }

        #endregion

        #region private object[] OnEndLog(IAsyncResult result)

        /// <summary>
        /// Called when [end log].
        /// </summary>
        /// <param name="result">The <see cref="T:IAsyncResult"/> returned by a call to the <see cref="M:DiagnosticsServiceClient.OnBeginLog"/> method.</param>
        /// <returns></returns>
        private object[] OnEndLog(IAsyncResult result)
        {
            return new object[] 
            {
                ((IDiagnosticsService)this).EndLog(result)
            };
        }

        #endregion

        #region private void OnLogCompleted(object state)

        /// <summary>
        /// Called when [log completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnLogCompleted(object state)
        {
            if (this.logCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;

                this.logCompleted(this, new LogCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void LogAsync(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity)

        /// <summary>
        /// Logs the async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="element">The element.</param>
        /// <param name="identity">The identity.</param>
        public void LogAsync(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity)
        {
            this.LogAsync(contract, dictionary, element, identity, null);
        }

        #endregion

        #region public void LogAsync(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, object state)

        /// <summary>
        /// Logs the async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="element">The element.</param>
        /// <param name="identity">The identity.</param>
        /// <param name="state">State of the user.</param>
        public void LogAsync(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, object state)
        {
            if (this.onBeginLogDelegate == null)
            {
                this.onBeginLogDelegate = new BeginOperationDelegate(this.OnBeginLog);
            }

            if (this.onEndLogDelegate == null)
            {
                this.onEndLogDelegate = new EndOperationDelegate(this.OnEndLog);
            }

            if (this.onLogCompletedDelegate == null)
            {
                this.onLogCompletedDelegate = new SendOrPostCallback(this.OnLogCompleted);
            }

            base.InvokeAsync(
                this.onBeginLogDelegate, 
                new object[] { contract, dictionary, element, identity }, 
                this.onEndLogDelegate, 
                this.onLogCompletedDelegate, 
                state);
        }

        #endregion

        #region IAsyncResult IDiagnosticsService.BeginUpdateProcessExitInformation(int processId, DateTime startTime, DateTime exitTime, int exitCode, AsyncCallback callback, object state)

        /// <summary>
        /// Begins an asynchronous operation to update process exit information.
        /// </summary>
        /// <param name="processId">The process Id representing the <see cref="T:Diagnostics.Process"/> for which details about how and when it exited should be published.</param>
        /// <param name="startTime">The process start time.</param>
        /// <param name="exitTime">The process exit time.</param>
        /// <param name="exitCode">The process exit code.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete. </param>
        /// <param name="state">A user-provided state object.</param>
        /// <returns>An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        IAsyncResult IDiagnosticsService.BeginUpdateProcessExitInformation(int processId, DateTime startTime, DateTime exitTime, int exitCode, AsyncCallback callback, object state)
        {
            return Channel.BeginUpdateProcessExitInformation(processId, startTime, exitTime, exitCode, callback, state);
        }

        #endregion

        #region void IDiagnosticsService.EndUpdateProcessExitInformation(IAsyncResult result)

        /// <summary>
        /// Ends an asynchronous operation to update process exit information.
        /// </summary>
        /// <param name="result">The result of the asynchronous operation to update process exit information.</param>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        void IDiagnosticsService.EndUpdateProcessExitInformation(IAsyncResult result)
        {
            Channel.EndUpdateProcessExitInformation(result);
        }

        #endregion

        #region private IAsyncResult OnBeginUpdateProcessExitInformation(object[] values, AsyncCallback callback, object state)

        /// <summary>
        /// Called when [begin update process exit information].
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private IAsyncResult OnBeginUpdateProcessExitInformation(object[] values, AsyncCallback callback, object state)
        {
            int processId = (int) values[0];
            
            DateTime startTime = (DateTime) values[1];
            
            DateTime exitTime = (DateTime) values[2];
            
            int exitCode = (int) values[3];

            return ((IDiagnosticsService)this).BeginUpdateProcessExitInformation(processId, startTime, exitTime, exitCode, callback, state);
        }

        #endregion

        #region private object[] OnEndUpdateProcessExitInformation(IAsyncResult result)

        /// <summary>
        /// Called when [end update process exit information].
        /// </summary>
        /// <param name="result">The <see cref="T:IAsyncResult"/> returned by a call to the <see cref="M:DiagnosticsServiceClient.OnBeginEndUpdateProcessExitInformation"/> method.</param>
        /// <returns></returns>
        private object[] OnEndUpdateProcessExitInformation(IAsyncResult result)
        {
            ((IDiagnosticsService)this).EndUpdateProcessExitInformation(result);
            
            return null;
        }

        #endregion

        #region private void OnUpdateProcessExitInformationCompleted(object state)

        /// <summary>
        /// Called when [update process exit information completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnUpdateProcessExitInformationCompleted(object state)
        {
            if (this.updateProcessExitInformationCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;
                this.updateProcessExitInformationCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void UpdateProcessExitInformationAsync(int processId, DateTime startTime, DateTime exitTime, int exitCode)

        /// <summary>
        /// Updates the process exit information async.
        /// </summary>
        /// <param name="processId">The process id.</param>
        /// <param name="startTime">The start time.</param>
        /// <param name="exitTime">The exit time.</param>
        /// <param name="exitCode">The exit code.</param>
        public void UpdateProcessExitInformationAsync(int processId, DateTime startTime, DateTime exitTime, int exitCode)
        {
            this.UpdateProcessExitInformationAsync(processId, startTime, exitTime, exitCode, null);
        }

        #endregion

        #region public void UpdateProcessExitInformationAsync(int processId, DateTime startTime, DateTime exitTime, int exitCode, object state)

        /// <summary>
        /// Updates the process exit information async.
        /// </summary>
        /// <param name="processId">The process id.</param>
        /// <param name="startTime">The start time.</param>
        /// <param name="exitTime">The exit time.</param>
        /// <param name="exitCode">The exit code.</param>
        /// <param name="state">State of the user.</param>
        public void UpdateProcessExitInformationAsync(int processId, DateTime startTime, DateTime exitTime, int exitCode, object state)
        {
            if (this.onBeginUpdateProcessExitInformationDelegate == null)
            {
                this.onBeginUpdateProcessExitInformationDelegate = new BeginOperationDelegate(this.OnBeginUpdateProcessExitInformation);
            }

            if (this.onEndUpdateProcessExitInformationDelegate == null)
            {
                this.onEndUpdateProcessExitInformationDelegate = new EndOperationDelegate(this.OnEndUpdateProcessExitInformation);
            }

            if (this.onUpdateProcessExitInformationCompletedDelegate == null)
            {
                this.onUpdateProcessExitInformationCompletedDelegate = new SendOrPostCallback(this.OnUpdateProcessExitInformationCompleted);
            }

            base.InvokeAsync(
                this.onBeginUpdateProcessExitInformationDelegate, 
                new object[] { processId, startTime, exitTime, exitCode }, 
                this.onEndUpdateProcessExitInformationDelegate, 
                this.onUpdateProcessExitInformationCompletedDelegate, 
                state);
        }

        #endregion

        #region IAsyncResult IDiagnosticsService.BeginRegisterTeamFoundationServer(TeamFoundationServerDataContract contract, AsyncCallback callback, object state)

        /// <summary>
        /// Begins an asynchronous operation to register the Team Foundation Server specified by the supplied <see cref="T:Uri"/> to the database.
        /// </summary>
        /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.TeamFoundationServerDataContract"/> representing the Team Foundation Server to be registered within the database.</param>
        /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete. </param>
        /// <param name="state">A user-provided state object.</param>
        /// <returns>An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.</returns>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        IAsyncResult IDiagnosticsService.BeginRegisterTeamFoundationServer(TeamFoundationServerDataContract contract, AsyncCallback callback, object state)
        {
            return Channel.BeginRegisterTeamFoundationServer(contract, callback, state);
        }

        #endregion

        #region void IDiagnosticsService.EndRegisterTeamFoundationServer(IAsyncResult result)

        /// <summary>
        /// Ends an asynchronous operation to register a Team Foundation Server to the database.
        /// </summary>
        /// <param name="result">The result of the asynchronous operation to update process exit information.</param>
        [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
        void IDiagnosticsService.EndRegisterTeamFoundationServer(IAsyncResult result)
        {
            Channel.EndRegisterTeamFoundationServer(result);
        }

        #endregion

        #region private IAsyncResult OnBeginRegisterTeamFoundationServer(object[] values, AsyncCallback callback, object state)

        /// <summary>
        /// Called when [begin register team foundation server].
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        private IAsyncResult OnBeginRegisterTeamFoundationServer(object[] values, AsyncCallback callback, object state)
        {
            TeamFoundationServerDataContract contract = values[0] as TeamFoundationServerDataContract;

            return ((IDiagnosticsService)this).BeginRegisterTeamFoundationServer(contract, callback, state);
        }

        #endregion

        #region private object[] OnEndRegisterTeamFoundationServer(IAsyncResult result)

        /// <summary>
        /// Called when [end register team foundation server].
        /// </summary>
        /// <param name="result">The <see cref="T:IAsyncResult"/> returned by a call to the <see cref="M:DiagnosticsServiceClient.OnBeginRegisterTeamFoundationServer"/> method.</param>
        /// <returns></returns>
        private object[] OnEndRegisterTeamFoundationServer(IAsyncResult result)
        {
            ((IDiagnosticsService)this).EndRegisterTeamFoundationServer(result);

            return null;
        }

        #endregion

        #region private void OnRegisterTeamFoundationServerCompleted(object state)

        /// <summary>
        /// Called when [register team foundation server completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnRegisterTeamFoundationServerCompleted(object state)
        {
            if (this.registerTeamFoundationServerCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;

                this.registerTeamFoundationServerCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void RegisterTeamFoundationServerAsync(TeamFoundationServerDataContract contract)

        /// <summary>
        /// Registers the team foundation server async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        public void RegisterTeamFoundationServerAsync(TeamFoundationServerDataContract contract)
        {
            this.RegisterTeamFoundationServerAsync(contract, null);
        }

        #endregion

        #region public void RegisterTeamFoundationServerAsync(TeamFoundationServerDataContract contract, object state)

        /// <summary>
        /// Registers the team foundation server async.
        /// </summary>
        /// <param name="contract">The contract.</param>
        /// <param name="state">State of the user.</param>
        public void RegisterTeamFoundationServerAsync(TeamFoundationServerDataContract contract, object state)
        {
            if (this.onBeginRegisterTeamFoundationServerDelegate == null)
            {
                this.onBeginRegisterTeamFoundationServerDelegate = new BeginOperationDelegate(this.OnBeginRegisterTeamFoundationServer);
            }

            if (this.onEndRegisterTeamFoundationServerDelegate == null)
            {
                this.onEndRegisterTeamFoundationServerDelegate = new EndOperationDelegate(this.OnEndRegisterTeamFoundationServer);
            }

            if (this.onRegisterTeamFoundationServerCompletedDelegate == null)
            {
                this.onRegisterTeamFoundationServerCompletedDelegate = new SendOrPostCallback(this.OnRegisterTeamFoundationServerCompleted);
            }

            base.InvokeAsync(
                this.onBeginRegisterTeamFoundationServerDelegate, 
                new object[] { contract },
                this.onEndRegisterTeamFoundationServerDelegate, 
                this.onRegisterTeamFoundationServerCompletedDelegate,
                state);
        }

        #endregion

        #region private IAsyncResult OnBeginOpen(object[] inValues, AsyncCallback callback, object state)

        /// <summary>
        /// Called when [begin open].
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="state">State of the async.</param>
        /// <returns></returns>
        private IAsyncResult OnBeginOpen(object[] values, AsyncCallback callback, object state)
        {
            return ((ICommunicationObject)this).BeginOpen(callback, state);
        }

        #endregion

        #region private object[] OnEndOpen(IAsyncResult result)

        /// <summary>
        /// Called when [end open].
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        private object[] OnEndOpen(IAsyncResult result)
        {
            ((ICommunicationObject)this).EndOpen(result);
            return null;
        }

        #endregion

        #region private void OnOpenCompleted(object state)

        /// <summary>
        /// Called when [open completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnOpenCompleted(object state)
        {
            if (this.openCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;
                this.openCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void OpenAsync()

        /// <summary>
        /// Opens the async.
        /// </summary>
        public void OpenAsync()
        {
            this.OpenAsync(null);
        }

        #endregion

        #region public void OpenAsync(object state)

        /// <summary>
        /// Opens the async.
        /// </summary>
        /// <param name="state">State of the user.</param>
        public void OpenAsync(object state)
        {
            if (this.onBeginOpenDelegate == null)
            {
                this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
            }

            if (this.onEndOpenDelegate == null)
            {
                this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
            }

            if (this.onOpenCompletedDelegate == null)
            {
                this.onOpenCompletedDelegate = new SendOrPostCallback(this.OnOpenCompleted);
            }

            base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, state);
        }

        #endregion

        #region private IAsyncResult OnBeginClose(object[] values, AsyncCallback callback, object state)

        /// <summary>
        /// Called when [begin close].
        /// </summary>
        /// <param name="values">An object array containing the values required to invoke the service operation.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="state">State of the async.</param>
        /// <returns></returns>
        private IAsyncResult OnBeginClose(object[] values, AsyncCallback callback, object state)
        {
            return ((ICommunicationObject)this).BeginClose(callback, state);
        }

        #endregion

        #region private object[] OnEndClose(IAsyncResult result)

        /// <summary>
        /// Called when [end close].
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        private object[] OnEndClose(IAsyncResult result)
        {
            ((ICommunicationObject)this).EndClose(result);
            return null;
        }

        #endregion

        #region private void OnCloseCompleted(object state)

        /// <summary>
        /// Called when [close completed].
        /// </summary>
        /// <param name="state">The state.</param>
        private void OnCloseCompleted(object state)
        {
            if (this.closeCompleted != null)
            {
                InvokeAsyncCompletedEventArgs e = (InvokeAsyncCompletedEventArgs)state;

                this.closeCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        #endregion

        #region public void CloseAsync()

        /// <summary>
        /// Closes the async.
        /// </summary>
        public void CloseAsync()
        {
            this.CloseAsync(null);
        }

        #endregion

        #region public void CloseAsync(object state)

        /// <summary>
        /// Closes the async.
        /// </summary>
        /// <param name="state">State of the user.</param>
        public void CloseAsync(object state)
        {
            if (this.onBeginCloseDelegate == null)
            {
                this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
            }

            if (this.onEndCloseDelegate == null)
            {
                this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
            }

            if (this.onCloseCompletedDelegate == null)
            {
                this.onCloseCompletedDelegate = new SendOrPostCallback(this.OnCloseCompleted);
            }

            base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, state);
        }

        #endregion

        #region protected override IDiagnosticsService CreateChannel()

        /// <summary>
        /// Returns a new channel from the client to the service.
        /// </summary>
        /// <returns>
        /// A channel of type <paramref name="TChannel"/> that identifies the type of service contract encapsulated by this client object (proxy).
        /// </returns>
        protected override IDiagnosticsService CreateChannel()
        {
            return new DiagnosticsServiceClientChannel(this);
        }

        #endregion

        #region private class DiagnosticsServiceClientChannel : ChannelBase<IDiagnosticsService>, IDiagnosticsService

        /// <summary>
        /// Provides a custom channel used by the <see cref="T:DiagnosticsServiceClient"/> class to call service operations.
        /// </summary>
        private class DiagnosticsServiceClientChannel : ChannelBase<IDiagnosticsService>, IDiagnosticsService
        {
            #region public DiagnosticsServiceClientChannel(ClientBase<IDiagnosticsService> client) : base(client)

            /// <summary>
            /// Initializes a new instance of the <see cref="T:DiagnosticsServiceClientChannel"/> class.
            /// </summary>
            /// <param name="client">The <see cref="T:ServiceModel.ClientBase`1.ChannelBase`1"/> object used to initialize the new instance of the class.</param>
            public DiagnosticsServiceClientChannel(ClientBase<IDiagnosticsService> client) : base(client)
            {
            } 

            #endregion

            #region public IAsyncResult BeginPublishException(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)

            /// <summary>
            /// Begins an asynchronous operation that publishes the exception information contained within the specified <see cref="T:CodePlex.Diagnostics.Contracts.ExceptionDataContract"/> to the database.
            /// </summary>
            /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.ExceptionDataContract"/> containing the exception information to be published to the database.</param>
            /// <param name="dictionary">A <see cref="T:Collections.Generic.Dictionary`2"/> containing name value pairs associated with this exception.</param>
            /// <param name="element">A <see cref="T:Xml.Linq.XElement"/> representing an xml element to be associated with this exception.</param>
            /// <param name="identity">The <see cref="T:CodePlex.Diagnostics.Contracts.IIdentityDataContract"/> containing the identity information to be published to the database.</param>
            /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
            /// <param name="state">A user-provided state object.</param>
            /// <returns>
            /// An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.
            /// </returns>
            public IAsyncResult BeginPublishException(ExceptionDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)
            {
                object[] args = new object[4];

                args[0] = contract;

                args[1] = dictionary;

                args[2] = element;

                args[3] = identity;

                return base.BeginInvoke("PublishException", args, callback, state);
            }

            #endregion

            #region public Guid EndPublishException(IAsyncResult result)

            /// <summary>
            /// Ends an asynchronous operation to publish an exception.
            /// </summary>
            /// <param name="result">The result of the asynchronous operation to publish an exception.</param>
            /// <returns>
            /// A <see cref="T:Guid"/> containing the publication Id of the exception published to the database.
            /// </returns>
            public Guid EndPublishException(IAsyncResult result)
            {
                object[] args = new object[0];
                
                return (Guid) base.EndInvoke("PublishException", args, result);
            }

            #endregion

            #region public IAsyncResult BeginLog(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)

            /// <summary>
            /// Begins an asynchronous operation that writes the <see cref="T:String"/> using the configured logging provider.
            /// </summary>
            /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.LogEntryDataContract"/> containing the log entry information to be published to the database.</param>
            /// <param name="dictionary">A <see cref="T:Collections.Generic.Dictionary`2"/> containing name value pairs associated with this log entry.</param>
            /// <param name="element">A <see cref="T:Xml.Linq.XElement"/> representing an xml element to be associated with this log entry.</param>
            /// <param name="identity">The <see cref="T:CodePlex.Diagnostics.Contracts.IIdentityDataContract"/> containing the identity information to be published to the database.</param>
            /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
            /// <param name="state">A user-provided state object.</param>
            /// <returns>
            /// An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.
            /// </returns>
            public IAsyncResult BeginLog(LogEntryDataContract contract, Dictionary<string, string> dictionary, XElement element, IIdentityDataContract identity, AsyncCallback callback, object state)
            {
                object[] args = new object[4];

                args[0] = contract;

                args[1] = dictionary;

                args[2] = element;

                args[3] = identity;

                return base.BeginInvoke("Log", args, callback, state);
            }

            #endregion

            #region public Guid EndLog(IAsyncResult result)

            /// <summary>
            /// Ends an asynchronous operation to write the specified log entry to the database.
            /// </summary>
            /// <param name="result">The result of the asynchronous operation to write the specified log entry to the database.</param>
            /// <returns>
            /// A <see cref="T:Guid"/> containing the publication Id of the log entry written to the database.
            /// </returns>
            public Guid EndLog(IAsyncResult result)
            {
                object[] args = new object[0];

                return (Guid) base.EndInvoke("Log", args, result);
            }

            #endregion

            #region public IAsyncResult BeginUpdateProcessExitInformation(int processId, DateTime startTime, DateTime exitTime, int exitCode, AsyncCallback callback, object state)

            /// <summary>
            /// Begins an asynchronous operation to update process exit information.
            /// </summary>
            /// <param name="processId">The process Id representing the <see cref="T:Diagnostics.Process"/> for which details about how and when it exited should be published.</param>
            /// <param name="startTime">The process start time.</param>
            /// <param name="exitTime">The process exit time.</param>
            /// <param name="exitCode">The process exit code.</param>
            /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
            /// <param name="state">A user-provided state object.</param>
            /// <returns>
            /// An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.
            /// </returns>
            public IAsyncResult BeginUpdateProcessExitInformation(int processId, DateTime startTime, DateTime exitTime, int exitCode, AsyncCallback callback, object state)
            {
                object[] args = new object[4];

                args[0] = processId;

                args[1] = startTime;

                args[2] = exitTime;

                args[3] = exitCode;

                return base.BeginInvoke("UpdateProcessExitInformation", args, callback, state);
            }

            #endregion

            #region public void EndUpdateProcessExitInformation(IAsyncResult result)

            /// <summary>
            /// Ends an asynchronous operation to update process exit information.
            /// </summary>
            /// <param name="result">The result of the asynchronous operation to update process exit information.</param>
            public void EndUpdateProcessExitInformation(IAsyncResult result)
            {
                object[] args = new object[0];

                base.EndInvoke("UpdateProcessExitInformation", args, result);
            }

            #endregion

            #region public IAsyncResult BeginRegisterTeamFoundationServer(TeamFoundationServerDataContract contract, AsyncCallback callback, object state)

            /// <summary>
            /// Begins an asynchronous operation to register the Team Foundation Server specified by the supplied <see cref="T:Uri"/> to the database.
            /// </summary>
            /// <param name="contract">The <see cref="T:CodePlex.Diagnostics.Contracts.TeamFoundationServerDataContract"/> representing the Team Foundation Server to be registered within the database.</param>
            /// <param name="callback">An optional asynchronous callback, to be called when the asynchronous operation is complete.</param>
            /// <param name="state">A user-provided state object.</param>
            /// <returns>
            /// An <see cref="T:IAsyncResult"/> that represents the asynchronous operation, which could still be pending.
            /// </returns>
            public IAsyncResult BeginRegisterTeamFoundationServer(TeamFoundationServerDataContract contract, AsyncCallback callback, object state)
            {
                object[] args = new object[1];

                args[0] = contract;

                return base.BeginInvoke("RegisterTeamFoundationServer", args, callback, state);
            }

            #endregion

            #region public void EndRegisterTeamFoundationServer(IAsyncResult result)

            /// <summary>
            /// Ends an asynchronous operation to register a Team Foundation Server to the database.
            /// </summary>
            /// <param name="result">The result of the asynchronous operation to update process exit information.</param>
            public void EndRegisterTeamFoundationServer(IAsyncResult result)
            {
                object[] args = new object[0];

                base.EndInvoke("RegisterTeamFoundationServer", args, result);
            }

            #endregion
        }

        #endregion
    }
}
